from tokens import openFile,closeFile,getToken
from tool import getTerm
import copy
import queue
# 读取文法，返回 序号-(规约生成符号,符号长度) 字典
def readGram(filename = 'gra.txt'):
    graMap = {}
    order = 0

    with open(filename,'r') as f:
        for gra in f.readlines():
            # 读取并分割左和右
            curGra = gra.replace('\n','').replace(' ','').replace('<','<').replace('\t','').split('→')
            length = 0
            # 右边
            right = curGra[1]
            # 遍历右边每一个符号
            while(len(right) > 0):
                # 如果是非终结符
                if right[0] != '<':
                    # print(right)
                    # 读取一个终结符
                    term = getTerm(right)
                    length += 1
                    right = right[len(term):]
                else:
                    pos = right.find('>')
                    length += 1
                    right = right[pos + 1:]

            graMap[str(order)] = (curGra[0],length)
            order += 1
    return graMap
# 读取下推自动机
def readMachine(filename = 'xtzdj.csv'):
    move = {}
    with open(filename,'r') as f:
        # 首先读入标题
        titles = f.readline().replace('\n','').split(',')[1:]
        # .replace('逗号',',')
        for i in range(len(titles)):
            if titles[i] == '逗号':
                titles[i] = ',';
        # 读取每一行
        for l in f.readlines():
            l = l.replace('\n','').split(',')
            # print(l)
            # print(titles)
            # print(len(l))
            # print(len(titles))
            move[l[0]] = {}
            for i in range(len(titles)):
                # 设置文字
                move[l[0]][titles[i]] = l[i + 1] 
            # print(l)
        # print(titles)
    # print(move)
    return move
# # 关键字常量
# CON_SYM = 0; # const
# VAR_SYM = 1; # var
# PRO_SYM = 2; # procedure
# BEG_SYM = 3; # begin
# END_SYM = 4; # end 
# OOD_SYM = 5; # ood
# IF_SYM = 6;  # if
# THE_SYM = 7; # then
# WHI_SYM = 8; # while
# DO_SYM = 9;     # do
# REA_SYM = 10;   # read
# CAL_SYM = 11;   # call
# WRI_SYM = 12;   # write
# # 符号常量
# GIV_SYM = 20;   # :=
# EQ_SYM = 21;    # =
# LB_SYM = 22;    # (
# RB_SYM = 23;    # )
# SEM_SYM = 24;   # ;
# COM_SYM = 25;   # ,
# DOT_SYM = 26;   # .
# # 自定义终结符常量
# ID_SYM = 30;    # 标识符
# UN_SYM = 31;    # 数字
# RE_SYM = 32;    # > < >= <=
# MN_SYM = 33;    # + -
# TD_SYM = 34;    # * /
# END_SYM = 35;   # #
# 类型序号-符号映射表，用于对应下推自动机
symTranMap = {0:'const',1:'var',2:'procedure',3:'begin',4:'end',5:'ood',6:'if',7:'then',8:'while',9:'do',10:'read',11:'call',
12:'write',20:':=',21:'=',22:'(',23:')',24:';',25:',',26:'.',30:'id',31:'un',32:'re',33:'mn',34:'td',35:'#'}

# 语法树
# class Tree:


# 分析代码，返回语法树
def analyseCode(filename = 'test.pl0'):
    # 读取下推自动机
    move = readMachine()
    # 读取文法
    gram = readGram()
    # 状态栈，初始状态下状态0进栈
    statusStack = ['0']
    # 符号栈
    symbleStack = []

    # 树根-树映射
    rootTreeMap = {}


    openFile(filename)
    tok = 'empty'
    while tok[0] != 35:
        if tok == 'empty':
            tok = getToken()
        # print('读到了%s %s %s'%(symTranMap[tok[0]],tok[1],tok[2]))
        # 获取下推自动机的表示方式
        sym = symTranMap[tok[0]]
        # print('stack top is ' + statusStack[-1])
        # print('sym is ' + sym)
        # print(move[statusStack[-1]][sym])
        # 得到状态-符号对应的动作
        action = move[statusStack[-1]][sym]
        # print('当前action为%s' % action)
        # 如果是移进
        if action[0] == 's':
            print('移进')
            # 推入状态栈
            statusStack.append(action[1:])
            # 推入符号栈
            symbleStack.append(sym)
            print('移进后状态栈为%s' % statusStack)
            print('移进后符号栈为%s\n' % symbleStack)
            # 清空
            tok = 'empty'
        # 如果是规约
        elif action[0] == 'r':
            print('进入规约')
            # 获取文法序号
            garNum = action[1:]
            # 获取文法
            gra = gram[garNum];
            print('规约前状态栈为%s' % statusStack)
            print('规约前符号栈为%s' % symbleStack)
            print('当前文法为%s 长度为%s' % (gra[0],gra[1]))
            
            symbs = []
            # 弹栈
            for i in range(gra[1]):

                statusStack.pop() # = statusStack[:-1]
                symb = symbleStack.pop() # = symbleStack[:-1]

                # # 如果还没有发现这棵树
                # if rootTreeMap.get(symb) == None:
                #     # 收集弹出符号直接做叶子
                symbs.append(symb)
                # # 如果发现了语法树
                # else:
                #     # 把语法树做叶子
                #     symbs.append(rootTreeMap[symb])
                #     # 做完叶子就删掉
                #     rootTreeMap.pop(symb)
            # 产生一颗新树放到映射里面
            rootTreeMap[gra[0]] = symbs
            # symbs.append(lastLevel)
            # curLevel[gra[0]] = symbs
                
            # # 保存当前层级
            # lastLevel = copy.deepcopy(curLevel)
            # # 清空当前层级
            # curLevel = {}
                #print(statusStack[-1])
                #print(symbleStack[-1])
            # 根据ACTION列进栈
            # statusStack.append(move[statusStack[-1]][symbleStack[-1]])

            symbleStack.append(gra[0])
            statusStack.append(move[statusStack[-1]][symbleStack[-1]])
            # symbleStack.append(sym)
            print('规约后状态栈为%s' % statusStack)
            print('规约后符号栈为%s\n' % symbleStack)

        else:
            print('出现错误')
            return
    # curLevel[symbleStack[-1]] = lastLevel
    # curLevel.append(lastLevel)
    closeFile(filename)
    return rootTreeMap

    
if __name__ == '__main__':
    # move = readMachine()
    # print(move['27']['end'])
    # print(move['23']['<表达式>'])
    # graMap = readGram();
    # print(graMap)
    
    # openFile()
    # tok = '.'
    # while tok[0] != 35:
    #     tok = getToken()

    #     print(symTranMap[tok[0]])
    # closeFile()
    treeNodes = analyseCode()
    
    
    # # 删除树的无限递归因素
    # for node in treeNodes.items():
    #     ls = node[1]
    #     for i in range(len(ls)):
    #         # 如果出现了递归推导
    #         if ls[i] == node[0]:
    #             print('递归推导%s'%ls[i])
    #             # 删除非终结符的特征
    #             ls[i] = ls[i][1:-1]
    #             print('递归推导->%s'%ls[i])

    print(treeNodes)
    # queue = queue.Queue()
    # # 把列表推进队列
    # queue.put(treeNodes['<程序>'])
    # tree = {'<程序>':treeNodes['<程序>']}
    # treeNodes.pop('<程序>')
    # while not queue.empty():
    #     curList = queue.get()
    #     # curList = tree[cur]
    #     # 遍历列表中的每一项
    #     for item in curList:
    #         # 如果发现非终结符，则需要扩展
    #         if item[0] == '<':
    #             # 首先把非终结符替换成字典
    #             curList.remove(item)
    #             # 把父节点-子节点添加进去
    #             curList.append((item,treeNodes[item]))
    #             # 把列表添加进去继续处理
    #             queue.put(treeNodes[item])
    #             # 从树删除
    #             # treeNodes.pop(item)
    #     #tree[cur] = treeNodes[cur]
    # print(tree)
    # print(treeNodes['<程序>'])